/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.cvut.fel.taskpro.data.manager;

import cz.cvut.fel.taskpro.data.entity.GroupTaskPro;
import cz.cvut.fel.taskpro.data.entity.Kantor;
import cz.cvut.fel.taskpro.data.entity.Student;
import cz.cvut.fel.taskpro.data.entity.Subject;
import cz.cvut.fel.taskpro.data.imanager.IGroupData;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;


/**
 * This class implement #{@link IGroupData} interface
 * @author Tom
 * @version 1.0. beta
 */
@Stateless
public class GroupData extends ObjectManager implements IGroupData {

    @Override
    public void addGroup(GroupTaskPro groupToAdd) {
        Subject pr = groupToAdd.getSubject();
        pr.addGroup(groupToAdd);
        super.add(groupToAdd);
    }

    @Override
    public List<GroupTaskPro> findGroupBySubjecst(List<Subject> subjects, Kantor loggedKantor) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<GroupTaskPro> groupQuery = cb.createQuery(GroupTaskPro.class);
        Root<GroupTaskPro> groupQueryRoot = groupQuery.from(GroupTaskPro.class);
        Predicate kantorPredicate = cb.equal(groupQueryRoot.get("kantor"), loggedKantor);
        List<Predicate> subjectsPredicate = new ArrayList<Predicate>();
        Iterator subIterator = subjects.iterator();
        while (subIterator.hasNext()) {
            subjectsPredicate.add(cb.equal(groupQueryRoot.get("subject"), subIterator.next()));
        }
        Predicate subjectPred = cb.or(subjectsPredicate.toArray(new Predicate[0]));
        groupQuery.distinct(true);
        groupQuery.where(cb.and(subjectPred, kantorPredicate));
        groupQuery.orderBy(cb.asc(groupQueryRoot.get("code")));
        TypedQuery typedQuery = em.createQuery(groupQuery);
        List<GroupTaskPro> resultList = typedQuery.getResultList();
        return resultList;
    }

    @Override
    public List<GroupTaskPro> findGroupBySubject(Subject subject, Kantor kantor) {
        Query q = em.createNamedQuery("Group.BySubject");
        q.setParameter("kantor", kantor);
        q.setParameter("subject", subject);
        List<GroupTaskPro> result = q.getResultList();
        return result;
    }

    @Override
    public List<GroupTaskPro> getGroupBySubjectAndCode(Subject subject, String code) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<GroupTaskPro> groupQuery = cb.createQuery(GroupTaskPro.class);
        Root<GroupTaskPro> rootGroupQuery = groupQuery.from(GroupTaskPro.class);
        Predicate codePredicate = cb.equal(rootGroupQuery.get("code"), code);
        Predicate subjectPredicate = cb.equal(rootGroupQuery.get("subject"), subject);
        groupQuery.distinct(true).where(cb.and(subjectPredicate, codePredicate)).orderBy(cb.asc(rootGroupQuery.get("code")));
        TypedQuery typedQuery = em.createQuery(groupQuery);
        List<GroupTaskPro> resultList = typedQuery.getResultList();
        return resultList;
    }

    @Override
    public List<GroupTaskPro> getGroupsBySubject(Subject subject) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<GroupTaskPro> groupQuery = cb.createQuery(GroupTaskPro.class);
        Root<GroupTaskPro> rootGroupQuery = groupQuery.from(GroupTaskPro.class);
        Predicate subjecPredicate = cb.equal(rootGroupQuery.get("subject"), subject);
        groupQuery.where(subjecPredicate).orderBy(cb.asc(rootGroupQuery.get("code")));
        TypedQuery typedQuery = em.createQuery(groupQuery);
        List<GroupTaskPro> resultList = typedQuery.getResultList();
        return resultList;

    }

    @Override
    public GroupTaskPro getGroupBySubjectAndStudent(Subject subject, Student student) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<GroupTaskPro> groupQuery = cb.createQuery(GroupTaskPro.class);
        Root<GroupTaskPro> rootGroupQuery = groupQuery.from(GroupTaskPro.class);
        Predicate subjecPredicate = cb.equal(rootGroupQuery.get("subject"), subject);
        Join<Student, GroupTaskPro> studentGroup = rootGroupQuery.join("mStudents");
        Predicate studentPredicate = cb.equal(studentGroup, student);
        groupQuery.where(cb.and(studentPredicate, subjecPredicate)).orderBy(cb.asc(rootGroupQuery.get("code")));
        TypedQuery typedQuery = em.createQuery(groupQuery);
        List<GroupTaskPro> resultList = typedQuery.getResultList();
        if (resultList.isEmpty()) {
            return null;
        }
        return resultList.get(0);
    }

    @Override
    public void updateGroup(GroupTaskPro groupToUpdate) {
        super.update(groupToUpdate);
    }

    @Override
    public void removeGroup(GroupTaskPro groupToRemove) {
        super.remove(groupToRemove);
    }
}
